package cc.opcol.iot.app.auth;

import cc.opcol.iot.app.AppConfiguration;
import cc.opcol.iot.app.util.MongodbUtil;
import cc.opcol.iot.app.vo.GeneralQueryCondition;
import cc.opcol.iot.app.vo.User;
import cc.opcol.iot.app.vo.UserSession;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class UserSessionService {
    private final static Logger logger = LoggerFactory.getLogger(UserSessionService.class);

    public static final String USER_NAMESPACES="opcol_user";
    public static final String APP_INFO_NAMESPACES="opcol_app_info";
    public Map<String, UserSession> sessions = new ConcurrentHashMap<>();
    @Autowired
    AppConfiguration appConfiguration;

    @Autowired
    MongoTemplate mongoTemplate;

    @PostConstruct
    public void initAdminUsername(){
        GeneralQueryCondition generalQueryCondition=new GeneralQueryCondition();
        generalQueryCondition.setWhere("{'username':'admin'}");
        User user=mongoTemplate.findOne(MongodbUtil.newQuery(generalQueryCondition),User.class,USER_NAMESPACES);
        if(user==null){
            User admin=new User();
            admin.set_id(new Date().getTime());
            admin.setUsername("admin");
            admin.setPassword("admin");
            mongoTemplate.save(admin,USER_NAMESPACES);
        }
        generalQueryCondition=new GeneralQueryCondition();
        generalQueryCondition.setWhere("{}");
        List map=mongoTemplate.find(MongodbUtil.newQuery(generalQueryCondition),Map.class,APP_INFO_NAMESPACES);
        if(map==null || map.size()==0){
            Map defaultApp=new HashMap<>();
            defaultApp.put("_id",new Date().getTime());
            defaultApp.put("appId","opcol");
            defaultApp.put("accessKey",(UUID.randomUUID().toString()).replaceAll("-",""));
            mongoTemplate.save(defaultApp,APP_INFO_NAMESPACES);
            map.add(defaultApp);
        }
        logger.debug("================APP AccessKey=============");
        for(Object mp:map){
            Map app=(Map)mp;
            logger.info(app.get("appId")+":"+app.get("accessKey"));
        }
        logger.debug("==========================================");



    }

    public void releaseDeadSession(){
        List<String> deadList=new ArrayList<>();
        for(String key : sessions.keySet()){
            UserSession userSession=sessions.get(key);
            if(new Date().getTime()-userSession.getTime()>appConfiguration.getSessionTimeOutTime()){
                deadList.add(key);
            }
        }
        for(String key:deadList){
            try {
                sessions.remove(key);
            }catch (Exception e){

            }
        }
    }

    public UserSession login(String username, String password) {
        UserSession userSession = new UserSession();
        GeneralQueryCondition generalQueryCondition=new GeneralQueryCondition();
        generalQueryCondition.setNamespace(UserSessionService.USER_NAMESPACES);
        generalQueryCondition.setWhere("{'username':'"+username+"'}");
        Map<String,Object> user=mongoTemplate.findOne(MongodbUtil.newQuery(generalQueryCondition),Map.class,USER_NAMESPACES);
        if(user==null){
            return userSession;
        }
        if (user.get("password").equals(password)) {
            userSession.setLogin(true);
            userSession.setAccessKey(createAccessKey());
            userSession.setSignatureKey(createSignatureKey());
            sessions.put(userSession.getAccessKey(),userSession);
        }
        return userSession;
    }

    private String createSignatureKey() {
        String id = UUID.randomUUID().toString().replaceAll("-", "");
        id = DigestUtils.md5Hex(id.getBytes()).substring(8, 24).toUpperCase();
        return id;
    }


    private String createAccessKey() {
        String id = UUID.randomUUID().toString().replaceAll("-", "");
        id = DigestUtils.md5Hex(id.getBytes()).substring(8, 24).toUpperCase();
        return id;
    }

    public boolean validate(String appId,String timestamp, String signature) {
        if(StringUtils.isBlank(timestamp) || StringUtils.isBlank(signature)){
            return false;
        }
        String accessKey=findAccessKey(appId);
        if(DigestUtils.md5Hex(accessKey+timestamp).toUpperCase().equals(signature.toUpperCase())){
            return true;
        }
        return false;
    }

    private String findAccessKey(String appId) {
        GeneralQueryCondition generalQueryCondition=new GeneralQueryCondition();
        generalQueryCondition.setWhere("{'appId':'"+appId+"'}");
        Map<String,Object> map=mongoTemplate.findOne(MongodbUtil.newQuery(generalQueryCondition),Map.class,APP_INFO_NAMESPACES);
        if(map==null){
            return "";
        }
        return (String)map.get("accessKey");
    }

    public boolean validateAccessKey(String accessKey){
        if(StringUtils.isBlank(accessKey)){
            return false;
        }
        UserSession session=sessions.get(accessKey);
        if(session==null) {
            return false;
        }
        return true;
    }
}
